/*
 * relength.c
 *
 *  Created on: 2021年7月27日
 *      Author: wangbing
 *      Email : mz8023yt@163.com
 */

#ifdef __cplusplus
extern "C"
{
#endif

#include <stdio.h>              // printf
#include <stdint.h>             // uint8_t

#include "relength.h"
#include "relength_config.h"

int relength_init(RELENGTH_HANDLE *handle, uint32_t sample_rate, uint32_t bit_width, uint32_t size)
{
    int ret = 0;

    if(NULL == handle)
    {
        return EINVAL;
    }

    if(sample_rate != 8000 && sample_rate != 16000)
    {
        return EINVAL;
    }

    if(bit_width != 1 && bit_width != 2)
    {
        return EINVAL;
    }

    if(handle->init)
    {
        return EREINIT;
    }

    handle->sample_rate = sample_rate;
    handle->bit_width = bit_width;

    ret = ringbuffer_init(&handle->ringbuffer, size);
    if(ret)
    {
        printf("err: ringbuffer init failed, ret = %d\n", ret);
        return ERROR;
    }

    handle->init = 1;
    return 0;
}

int relength_deinit(RELENGTH_HANDLE *handle)
{
    int ret = 0;

    if(!handle->init)
    {
        return ENOTINIT;
    }

    ret = ringbuffer_deinit(&handle->ringbuffer);
    if(ret)
    {
        printf("err: ringbuffer deinit failed, ret = %d\n", ret);
        return ERROR;
    }

    handle->init = 0;
    return 0;
}

int relength_read(RELENGTH_HANDLE *handle, RELENGTH_FRAME *frame)
{
    int ret = 0;

    if(NULL == handle || NULL == frame)
    {
        return EINVAL;
    }

    if(!handle->init)
    {
        return ENOTINIT;
    }

    ret = ringbuffer_read(&handle->ringbuffer, frame->buf, frame->len);
    if(ret)
    {
        return ret;
    }

    handle->pts_refer = handle->pts_refer + (frame->len * 1000000 / handle->bit_width / handle->sample_rate);
    frame->pts = handle->pts_refer;

    return 0;
}

int relength_write(RELENGTH_HANDLE *handle, RELENGTH_FRAME *frame)
{
    int ret = 0;

    if(NULL == handle || NULL == frame)
    {
        return EINVAL;
    }

    if(!handle->init)
    {
        return ENOTINIT;
    }

    if(ringbuffer_is_empty(&handle->ringbuffer))
    {
        /* 缓冲区为空, 直接将当前帧的时间戳更新为参考时间戳 */
        handle->pts_refer = frame->pts - (frame->len * 1000000 / handle->bit_width / handle->sample_rate);
    }
    else
    {
#if (1 == RELENGTH_FRAME_LOST_SUPPORT)
        /* 缓冲区非空, 需要判断新写入的帧时间戳是否合理 */

        /* 获取缓冲区已填充的音频数据长度 */
        uint32_t fill = ringbuffer_fill_length_get(&handle->ringbuffer);

        /* 根据 fill + frame.len 预测当前帧的 frame.pts 合理范围(±10ms) */
        uint64_t pts_forecast = handle->pts_refer + ((frame->len + fill) * 1000000 / handle->bit_width / handle->sample_rate);
        uint64_t pts_min = pts_forecast - 10000;
        uint64_t pts_max = pts_forecast + 10000;

        /* 判断实际的时间和预测的时间是否匹配 */
        if(frame->pts < pts_min || frame->pts >= pts_max)
        {
            // printf(".\n");
            ringbuffer_clean(&handle->ringbuffer);
            handle->pts_refer = frame->pts - (frame->len * 1000000 / handle->bit_width / handle->sample_rate);
        }
#endif /* RELENGTH_FRAME_LOST_SUPPORT */
    }

    ret = ringbuffer_write(&handle->ringbuffer, frame->buf, frame->len);
    if(ret)
    {
        printf("err: ringbuffer write failed, ret = %d\n", ret);
        return ret;
    }

    return 0;
}

#ifdef __cplusplus
}
#endif
